%token Name ("name") : Name
%token NumberLiteral ("number literal") : Constant
%token StringLiteral ("string literal") : Constant
%token QuoteLiteral ("quote literal") : Constant
%token StackSlotValueRef ("stack slot value ref") : Constant
%token StackSlotContextRef ("stack slot context ref") : Constant

%token '(', ')'
%token '[', ']', '[^'
%token '{', '}', '}+'

%shift ':'
%shift '*'
%shift '+'
%shift Name
%shift '`'

%xstart DQSTRING, SQSTRING, LDQSTRING, LSQSTRING
%xstart RDQSTRING, RSQSTRING, RLDQSTRING, RLSQSTRING
%xstart DQBYTES, SQBYTES, LDQBYTES, LSQBYTES
%xstart RDQBYTES, RSQBYTES, RLDQBYTES, RLSQBYTES

%goal GrammarModule
%goal ProgramModule
%goal InteractiveSegment % NewLine
%goal SingleExpression

%define pg.parser.usings (
    System,
    System.Collections.Generic,
    System.Collections.ObjectModel,
    System.Diagnostics,
    System.IO,
    System.Linq,
    System.Numerics,
    System.Text,
    ParserGenerator.CharacterMapping,
    ParserGenerator.CodeGeneration,
    ParserGenerator.Collections,
    ParserGenerator.Directives,
    ParserGenerator.Exceptions,
    ParserGenerator.Expressions,
    ParserGenerator.Extensions,
    ParserGenerator.GrammarConstruction,
    ParserGenerator.Input,
    ParserGenerator.LexicalAnalysis,
    ParserGenerator.LexicalDeclarations,
    ParserGenerator.LexicalExpressions,
    ParserGenerator.Output,
    ParserGenerator.SyntacticDeclarations,
    ParserGenerator.SyntacticExpressions,
    ParserGenerator.Statements,
    ParserGenerator.TypeDeclarations,
    ParserGenerator.TypeExpressions,
)

%define pg.parser.classname ProgramDescriptionParser
%define pg.parser.namespace ParserGenerator.Statements

%%

lower  = ['a'-'z']
upper  = ['A'-'Z']
digit  = ['0'-'9']
letter = lower | upper | '_'
name   = letter (letter | digit)*

line_terminator     = [  '\n' '\v' '\f' '\r' '\x85' '\u2028' '\u2029']
non_line_terminator = [^ '\n' '\v' '\f' '\r' '\x85' '\u2028' '\u2029']
non_line_terminator_ascii = ['\0'-'\t' '\x0E'-'\x7F']
non_line_terminator_byte  = ['\0'-'\t' '\x0E'-'\xFF']
any_ascii = ['\0'-'\x7F']
any_byte  = ['\0'-'\xFF']
any_char  = [^]

bin = ['0' '1']
oct = ['0'-'7']
hex = ['0'-'9' 'A'-'F' 'a'-'f']
hex_quad = hex hex hex hex
non_zero_digit = ['1'-'9']

decimal_integer     = non_zero_digit digit* | '0'+
binary_integer      = '0' ['b' 'B'] bin+
octal_integer       = '0' ['o' 'O'] oct+
hexadecimal_integer = '0' ['x' 'X'] hex+

float_number   = point_float | exponent_float
point_float    = int_part? fraction | int_part '.'
exponent_float = (int_part | point_float) exponent
int_part       = digit+
fraction       = '.' digit+
exponent       = ['e' 'E'] ['+' '-']? digit+

imaginary_number = (float_number | int_part) ['j' 'J']

"(" =>: Level++; yield '('
")" =>: Level--; yield ')'
"[" =>: Level++; yield '['
"]" =>: Level--; yield ']'
"[^" =>: Level++; yield '[^'
"{" =>: Level++; yield '{'
"}" =>: Level--; yield '}'
"}+" =>: Level--; yield '}+'

name                =>: ScanNameValue();      yield Name
decimal_integer     =>: ScanIntegerValue(10); yield NumberLiteral
binary_integer      =>: ScanIntegerValue(2);  yield NumberLiteral
octal_integer       =>: ScanIntegerValue(8);  yield NumberLiteral
hexadecimal_integer =>: ScanIntegerValue(16); yield NumberLiteral
float_number        =>: ScanFloatValue();     yield NumberLiteral
imaginary_number    =>: ScanComplexValue();   yield NumberLiteral

'$' decimal_integer =>: ScanIntegerValue(10, True); yield StackSlotValueRef
'@' decimal_integer =>: ScanIntegerValue(10, True); yield StackSlotContextRef

['u' 'U']? "\""     =>: BeginString(DQSTRING, False)
['u' 'U']? "\'"     =>: BeginString(SQSTRING, True)
['u' 'U']? "\"\"\"" =>: BeginString(LDQSTRING, False)
['u' 'U']? "\'\'\'" =>: BeginString(LSQSTRING, True)

['r' 'R']  "\""     =>: BeginString(RDQSTRING, False)
['r' 'R']  "\'"     =>: BeginString(RSQSTRING, True)
['r' 'R']  "\"\"\"" =>: BeginString(RLDQSTRING, False)
['r' 'R']  "\'\'\'" =>: BeginString(RLSQSTRING, True)

['b' 'B']  "\""     =>: BeginByteString(DQBYTES, False)
['b' 'B']  "\'"     =>: BeginByteString(SQBYTES, True)
['b' 'B']  "\"\"\"" =>: BeginByteString(LDQBYTES, False)
['b' 'B']  "\'\'\'" =>: BeginByteString(LSQBYTES, True)

(['b' 'B'] ['r' 'R'] | ['r' 'R'] ['b' 'B']) "\""     =>: BeginByteString(RDQBYTES, False)
(['b' 'B'] ['r' 'R'] | ['r' 'R'] ['b' 'B']) "\'"     =>: BeginByteString(RSQBYTES, True)
(['b' 'B'] ['r' 'R'] | ['r' 'R'] ['b' 'B']) "\"\"\"" =>: BeginByteString(RLDQBYTES, False)
(['b' 'B'] ['r' 'R'] | ['r' 'R'] ['b' 'B']) "\'\'\'" =>: BeginByteString(RLSQBYTES, True)

<DQSTRING, SQSTRING, LDQSTRING, LSQSTRING>:
    "\\" line_terminator =>: pass
    "\\\\" =>: AppendChar('\\')
    "\\\"" =>: AppendChar('\"')
    "\\\'" =>: AppendChar('\'')
    "\\a" =>: AppendChar('\a')
    "\\b" =>: AppendChar('\b')
    "\\t" =>: AppendChar('\t')
    "\\n" =>: AppendChar('\n')
    "\\v" =>: AppendChar('\v')
    "\\f" =>: AppendChar('\f')
    "\\r" =>: AppendChar('\r')
    "\\" oct =>: AppendEscape(1, True, True)
    "\\" oct oct =>: AppendEscape(2, True, True)
    "\\" oct oct oct =>: AppendEscape(3, True, True)
    "\\x" hex hex =>: AppendEscape(2, True, False)
    "\\u" hex_quad =>: AppendEscape(4, True, False)
    "\\U" hex_quad hex_quad =>: AppendEscape(8, True, False)

<DQSTRING,  SQSTRING,  LDQSTRING,  LSQSTRING, \
 RDQSTRING, RSQSTRING, RLDQSTRING, RLSQSTRING>:
    "\\" any_char =>: AppendTokenString()

<DQSTRING, RDQSTRING>:
    "\"" =>: EndString(); yield StringLiteral
<SQSTRING, RSQSTRING>:
    "\'" =>: EndString(); yield QuoteLiteral
<DQSTRING, RDQSTRING, SQSTRING, RSQSTRING>:
    non_line_terminator =>: AppendTokenString()

<LDQSTRING, RLDQSTRING>:
    "\"\"\"" =>: EndString(); yield StringLiteral
<LSQSTRING, RLSQSTRING>:
    "\'\'\'" =>: EndString(); yield StringLiteral
<LDQSTRING, RLDQSTRING, LSQSTRING, RLSQSTRING>:
    any_char =>: AppendTokenString()

<DQBYTES, SQBYTES, LDQBYTES, LSQBYTES>:
    "\\" line_terminator =>: pass
    "\\\\" =>: AppendByte('\\')
    "\\\"" =>: AppendByte('\"')
    "\\\'" =>: AppendByte('\'')
    "\\a" =>: AppendByte('\a')
    "\\b" =>: AppendByte('\b')
    "\\t" =>: AppendByte('\t')
    "\\n" =>: AppendByte('\n')
    "\\v" =>: AppendByte('\v')
    "\\f" =>: AppendByte('\f')
    "\\r" =>: AppendByte('\r')
    "\\" oct =>: AppendEscape(1, False, True)
    "\\" oct oct =>: AppendEscape(2, False, True)
    "\\" oct oct oct =>: AppendEscape(3, False, True)
    "\\x" hex hex =>: AppendEscape(2, False, False)

<DQBYTES,  SQBYTES,  LDQBYTES,  LSQBYTES, \
 RDQBYTES, RSQBYTES, RLDQBYTES, RLSQBYTES>:
    "\\" any_ascii =>: AppendTokenStringAsBytes()
    "\\" any_byte =>: raise SyntaxError(SR.NonAsciiByteMustBeXO)
    "\\" any_char =>: raise SyntaxError(SR.EscapedCharNotAscii)

<DQBYTES, RDQBYTES>:
    "\"" =>: EndByteString(); yield StringLiteral
<SQBYTES, RSQBYTES>:
    "\'" =>: EndByteString(); yield StringLiteral
<DQBYTES, RDQBYTES, SQBYTES, RSQBYTES>:
    non_line_terminator_ascii =>: AppendTokenStringAsBytes()
    non_line_terminator_byte =>: raise SyntaxError(SR.NonAsciiByteMustBeXO)
    non_line_terminator =>: raise SyntaxError(SR.CharNotByte)

<LDQBYTES, RLDQBYTES>:
    "\"\"\"" =>: EndByteString(); yield StringLiteral
<LSQBYTES, RLSQBYTES>:
    "\'\'\'" =>: EndByteString(); yield StringLiteral
<LDQBYTES, RLDQBYTES, LSQBYTES, RLSQBYTES>:
    any_ascii =>: AppendTokenStringAsBytes()
    any_byte =>: raise SyntaxError(SR.NonAsciiByteMustBeXO)
    any_char =>: raise SyntaxError(SR.CharNotByte)

<DQSTRING,  SQSTRING,  LDQSTRING,  LSQSTRING,  \
 RDQSTRING, RSQSTRING, RLDQSTRING, RLSQSTRING, \
 DQBYTES,   SQBYTES,   LDQBYTES,   LSQBYTES,   \
 RDQBYTES,  RSQBYTES,  RLDQBYTES,  RLSQBYTES>:
    default =>: raise UnterminatedString()

%%

StatementList as [Statement]:
    SimpleStatement NewLine => $1
    CompoundStatement =>:
        $$ = Sequence.Create($1)
    StatementList SimpleStatement NewLine =>:
        $$ = Sequence.Concat($1, $2)
    StatementList CompoundStatement =>:
        $$ = Sequence.Append($1, $2)

StatementSuite as [Statement]:
    SimpleStatement NewLine => $1
    NewLine Indent StatementList Unindent => $3

GrammarModule as ProgramDescription:
    GrammarDeclaration =>:
        let fragment = LexicalAnalysis.Name.New("fragment", SourceContext.New(@@.Begin, @@.Begin))
        let decorator = Expression.NewNameReference(fragment, ExpressionUsage.Load, fragment.Context)
        let name = LexicalAnalysis.Name.New(GetGrammarFragmentName(@@), fragment.Context)
        let decl = GrammarDeclaration.New(name, default([Expression]), default([KeywordArgument]),
                                          $1.Item1, $1.Item2, $1.Item3, $1.Item4,
                                          Sequence.Create(decorator), @@)
        $$ = ProgramDescription.NewGrammar(decl, @@)

GrammarDeclaration as (DirectiveDeclaration, TypeDeclaration, LexicalDeclaration, SyntacticDeclaration):
    DirectiveDeclaration TypeDeclaration '%%' NewLine LexicalDeclaration '%%' NewLine SyntacticDeclaration =>:
        let directiveDecl = $1
        let typeDecl = $2
        let lexDecl = $5
        let syntaxDecl = $8
        $$ = (directiveDecl, typeDecl, lexDecl, syntaxDecl)
    DirectiveDeclaration TypeDeclaration '%%' NewLine LexicalDeclaration =>:
        let directiveDecl = $1
        let typeDecl = $2
        let lexDecl = $5
        let syntaxDecl = SyntacticDeclaration.New(default([SyntacticRuleDeclaration]), @@)
        $$ = (directiveDecl, typeDecl, lexDecl, syntaxDecl)
    DirectiveDeclaration TypeDeclaration =>:
        let directiveDecl = $1
        let typeDecl = $2
        let lexAliasDecl = LexicalAliasDeclaration.New(default([LexicalAliasDeclarator]), @@)
        let lexStartRefSet = LexicalStartReferenceSet.New(default([Name]), True, False, @@)
        let lexRuleDecl = LexicalRuleDeclaration.New(lexStartRefSet, default([LexicalRuleDeclarator]), None, @@)
        let lexDecl = LexicalDeclaration.New(lexAliasDecl, lexRuleDecl, default([LexicalRuleDeclaration]), @@)
        let syntaxDecl = SyntacticDeclaration.New(default([SyntacticRuleDeclaration]), @@)
        $$ = (directiveDecl, typeDecl, lexDecl, syntaxDecl)

GrammarDeclarationSuite as (DirectiveDeclaration, TypeDeclaration, LexicalDeclaration, SyntacticDeclaration):
    'pass' NewLine =>:
        let directiveDecl = DirectiveDeclaration.New(default([Directive]), @@)
        let typeDecl = TypeDeclaration.New(default([TypeDeclarator]), @@)
        let lexAliasDecl = LexicalAliasDeclaration.New(default([LexicalAliasDeclarator]), @@)
        let lexStartRefSet = LexicalStartReferenceSet.New(default([Name]), True, False, @@)
        let lexRuleDecl = LexicalRuleDeclaration.New(lexStartRefSet, default([LexicalRuleDeclarator]), None, @@)
        let lexDecl = LexicalDeclaration.New(lexAliasDecl, lexRuleDecl, default([LexicalRuleDeclaration]), @@)
        let syntaxDecl = SyntacticDeclaration.New(default([SyntacticRuleDeclaration]), @@)
        $$ = (directiveDecl, typeDecl, lexDecl, syntaxDecl)
    NewLine Indent 'pass' NewLine Unindent =>:
        let directiveDecl = DirectiveDeclaration.New(default([Directive]), @@)
        let typeDecl = TypeDeclaration.New(default([TypeDeclarator]), @@)
        let lexAliasDecl = LexicalAliasDeclaration.New(default([LexicalAliasDeclarator]), @@)
        let lexStartRefSet = LexicalStartReferenceSet.New(default([Name]), True, False, @@)
        let lexRuleDecl = LexicalRuleDeclaration.New(lexStartRefSet, default([LexicalRuleDeclarator]), None, @@)
        let lexDecl = LexicalDeclaration.New(lexAliasDecl, lexRuleDecl, default([LexicalRuleDeclaration]), @@)
        let syntaxDecl = SyntacticDeclaration.New(default([SyntacticRuleDeclaration]), @@)
        $$ = (directiveDecl, typeDecl, lexDecl, syntaxDecl)
    NewLine Indent DirectiveDeclaration TypeDeclaration '%%' NewLine LexicalDeclaration '%%' NewLine SyntacticDeclaration Unindent =>:
        let directiveDecl = $3
        let typeDecl = $4
        let lexDecl = $7
        let syntaxDecl = $10
        $$ = (directiveDecl, typeDecl, lexDecl, syntaxDecl)
    NewLine Indent DirectiveDeclaration TypeDeclaration '%%' NewLine LexicalDeclaration Unindent =>:
        let directiveDecl = $3
        let typeDecl = $4
        let lexDecl = $7
        let syntaxDecl = SyntacticDeclaration.New(default([SyntacticRuleDeclaration]), @@)
        $$ = (directiveDecl, typeDecl, lexDecl, syntaxDecl)
    NewLine Indent DirectiveDeclaration TypeDeclaration Unindent =>:
        let directiveDecl = $3
        let typeDecl = $4
        let lexAliasDecl = LexicalAliasDeclaration.New(default([LexicalAliasDeclarator]), @@)
        let lexStartRefSet = LexicalStartReferenceSet.New(default([Name]), True, False, @@)
        let lexRuleDecl = LexicalRuleDeclaration.New(lexStartRefSet, default([LexicalRuleDeclarator]), None, @@)
        let lexDecl = LexicalDeclaration.New(lexAliasDecl, lexRuleDecl, default([LexicalRuleDeclaration]), @@)
        let syntaxDecl = SyntacticDeclaration.New(default([SyntacticRuleDeclaration]), @@)
        $$ = (directiveDecl, typeDecl, lexDecl, syntaxDecl)

CompoundStatement as Statement:
    'if' TestExpression ':' StatementSuite => Statement.NewIf($2, $4, default([Statement]), @@)
    'if' TestExpression ':' StatementSuite 'else' ':' StatementSuite => Statement.NewIf($2, $4, $7, @@)
    'if' TestExpression ':' StatementSuite ElseIfList 'else' ':' StatementSuite => Statement.NewIf($2, $4, ExpandElseIfList($5, @8, $8), @@)
    'if' TestExpression ':' StatementSuite ElseIfList => Statement.NewIf($2, $4, ExpandElseIfList($5, @5, default([Statement])), @@)
    'while' TestExpression ':' StatementSuite => Statement.NewWhile($2, $4, default([Statement]), @@)
    'while' TestExpression ':' StatementSuite 'else' ':' StatementSuite => Statement.NewWhile($2, $4, $7, @@)
    'for' ExpressionList 'in' TestExpressionList ':' StatementSuite => CreateForStatement(False, $2, $4, $6, default([Statement]), @@)
    'for' ExpressionList 'in' TestExpressionList ':' StatementSuite 'else' ':' StatementSuite => CreateForStatement(False, $2, $4, $6, $9, @@)
    'async' 'for' ExpressionList 'in' TestExpressionList ':' StatementSuite => CreateForStatement(True, $3, $5, $7, default([Statement]), @@)
    'async' 'for' ExpressionList 'in' TestExpressionList ':' StatementSuite 'else' ':' StatementSuite => CreateForStatement(True, $3, $5, $7, $10, @@)
    'with' WithItemList ':' StatementSuite => Statement.NewWith(False, $2, $4, @@)
    'async' 'with' WithItemList ':' StatementSuite => Statement.NewWith(True, $3, $5, @@)
    'try' ':' StatementSuite 'finally' ':' StatementSuite => Statement.NewTry($3, default([ExceptionHandler]), default([Statement]), $6, @@)
    'try' ':' StatementSuite ExceptionHandlers 'else' ':' StatementSuite 'finally' ':' StatementSuite => Statement.NewTry($3, $4, $7, $10, @@)
    'try' ':' StatementSuite ExceptionHandlers 'else' ':' StatementSuite => Statement.NewTry($3, $4, $7, default([Statement]), @@)
    'try' ':' StatementSuite ExceptionHandlers 'finally' ':' StatementSuite => Statement.NewTry($3, $4, default([Statement]), $7, @@)
    'try' ':' StatementSuite ExceptionHandlers => Statement.NewTry($3, $4, default([Statement]), default([Statement]), @@)

    'def' name '(' FunctionParameterList ')' '->' TypeExpression ':' StatementSuite => CreateFunctionStatement(False, $2, $4, $9, default([Expression]), $7, @@)
    'def' name '(' FunctionParameterList ')' ':' StatementSuite => CreateFunctionStatement(False, $2, $4, $7, default([Expression]), None, @@)
    'async' 'def' name '(' FunctionParameterList ')' '->' TypeExpression ':' StatementSuite => CreateFunctionStatement(True, $3, $5, $10, default([Expression]), $8, @@)
    'async' 'def' name '(' FunctionParameterList ')' ':' StatementSuite => CreateFunctionStatement(True, $3, $5, $8, default([Expression]), None, @@)

    DecoratorList 'def' name '(' FunctionParameterList ')' '->' TypeExpression ':' StatementSuite => CreateFunctionStatement(False, $3, $5, $10, $1, $8, @@)
    DecoratorList 'def' name '(' FunctionParameterList ')' ':' StatementSuite => CreateFunctionStatement(False, $3, $5, $8, $1, None, @@)
    DecoratorList 'async' 'def' name '(' FunctionParameterList ')' '->' TypeExpression ':' StatementSuite => CreateFunctionStatement(True, $4, $6, $11, $1, $9, @@)
    DecoratorList 'async' 'def' name '(' FunctionParameterList ')' ':' StatementSuite => CreateFunctionStatement(True, $4, $6, $9, $1, None, @@)

    'class' name OptionalCallArgumentList ':' StatementSuite =>:
        _validator.CheckForbiddenName($2)
        let decl = ClassDeclaration.New($2, $3.Item1, $3.Item2, $5, default([Expression]), @@)
        $$ = Statement.NewClass(decl, @@)
    DecoratorList 'class' name OptionalCallArgumentList ':' StatementSuite =>:
        _validator.CheckForbiddenName($3)
        let decl = ClassDeclaration.New($3, $4.Item1, $4.Item2, $6, $1, @@)
        $$ = Statement.NewClass(decl, @@)

    'grammar' name OptionalCallArgumentList ':' GrammarDeclarationSuite =>:
        _validator.CheckForbiddenName($2)
        let decl = GrammarDeclaration.New($2, $3.Item1, $3.Item2, $5.Item1, $5.Item2, $5.Item3, $5.Item4, default([Expression]), @@)
        $$ = Statement.NewGrammar(decl, @@)
    DecoratorList 'grammar' name OptionalCallArgumentList ':' GrammarDeclarationSuite =>:
        _validator.CheckForbiddenName($3)
        let decl = GrammarDeclaration.New($3, $4.Item1, $4.Item2, $6.Item1, $6.Item2, $6.Item3, $6.Item4, $1, @@)
        $$ = Statement.NewGrammar(decl, @@)

ElseIfList as [(Expression, [Statement], SourceContext)]:
    ElseIf => Sequence.Create($1)
    ElseIfList ElseIf => Sequence.Append($1, $2)

ElseIf as (Expression, [Statement], SourceContext):
    'elif' TestExpression ':' StatementSuite => ($2, $4, @@)

WithItemList as [WithItem]:
    WithItem => Sequence.Create($1)
    WithItemList ',' WithItem => Sequence.Append($1, $3)

WithItem as WithItem:
    TestExpression 'as' Expression =>:
        _validator.SetUsage($3, ExpressionUsage.Store)
        $$ = WithItem.New($1, $3, @@)
    TestExpression => WithItem.New($1, None, @@)

DecoratorList as [Expression]:
    Decorator => Sequence.Create($1)
    DecoratorList Decorator => Sequence.Append($1, $2)

Decorator as Expression:
    '@' DottedNameExpression NewLine => $2
    '@' DottedNameExpression CallArgumentList NewLine =>:
        _validator.CheckArgumentCount($3.Item1, $3.Item2, @3)
        $$ = Expression.NewCall($2, $3.Item1, $3.Item2, @@)

ExceptionHandlers as [ExceptionHandler]:
    ExceptionHandlerList =>:
        CheckExceptionHandlerList($1)
        $$ = $1

ExceptionHandlerList as [ExceptionHandler]:
    ExceptionHandler => Sequence.Create($1)
    ExceptionHandlerList ExceptionHandler => Sequence.Append($1, $2)

ExceptionHandler as ExceptionHandler:
    'except' TypeExpression 'as' name ':' StatementSuite =>:
        _validator.CheckForbiddenName($4)
        $$ = ExceptionHandler.New($2, $4, $6, @@)
    'except' TypeExpression ':' StatementSuite => ExceptionHandler.New($2, None, $4, @@)
    'except' ':' StatementSuite => ExceptionHandler.New(None, None, $3, @@)

SimpleStatement as [Statement]:
    SmallStatementList => $1
    SmallStatementList ';' => $1

SmallStatementList as [Statement]:
    SmallStatement => Sequence.Create($1)
    SmallStatementList ';' SmallStatement => Sequence.Append($1, $3)

SmallStatement as Statement:
    ExpressionStatement => $1
    'let' name ':' TypeExpression '=' TestExpression => Statement.NewBind(False, $2, $4, $6, @@)
    'let' name '=' TestExpression => Statement.NewBind(False, $2, None, $4, @@)
    'var' name ':' TypeExpression '=' TestExpression => Statement.NewBind(True, $2, $4, $6, @@)
    'var' name '=' TestExpression => Statement.NewBind(True, $2, None, $4, @@)
    'del' ExpressionListNoTrailingComma ','? =>:
        _validator.SetUsage($2, ExpressionUsage.Delete)
        $$ = Statement.NewDelete($2, @@)
    'pass' => Statement.NewPass(@@)
    'break' => Statement.NewBreak(@@)
    'continue' => Statement.NewContinue(@@)
    'return' TestExpressionList => Statement.NewReturn($2, @@)
    'return' => Statement.NewReturn(None, @@)
    'raise' => Statement.NewRaise(None, None, @@)
    'raise' TestExpression => Statement.NewRaise($2, None, @@)
    'raise' TestExpression 'from' TestExpression => Statement.NewRaise($2, $4, @@)
    YieldExpression => Statement.NewExpr($1, @@)
    'import' DottedNameAsList => Statement.NewImport($2, @@)
    'from' ModuleSpecifier 'import' '*' =>:
        var star = LexicalAnalysis.Name.New("*", @4)
        var dotted = DottedName.New(Sequence.Create(star), @4)
        var bind = ImportBinding.New(dotted, None, @4)
        var list = Sequence.Create(bind)
        $$ = Statement.NewFromImport($2.Item1, list, $2.Item2, @@)
    'from' ModuleSpecifier 'import' '(' NameAsList ','? ')' => Statement.NewFromImport($2.Item1, $5, $2.Item2, @@)
    'from' ModuleSpecifier 'import' NameAsList => Statement.NewFromImport($2.Item1, $4, $2.Item2, @@)
    'from' ModuleSpecifier 'import' NameAsList ',' =>:
        ErrorImportTrailingComma(@5)
    'global' NameList => Statement.NewGlobal($2, @@)
    'nonlocal' NameList => Statement.NewNonlocal($2, @@)
    'assert' TestExpression => Statement.NewAssert($2, None, @@)
    'assert' TestExpression ',' TestExpression => Statement.NewAssert($2, $4, @@)

ExpressionStatement as Statement:
    TestOrStarredExpressionList AugmentedAssignOp YieldExpression => CreateAugmentedAssignStatement($1, $2, $3, @2)
    TestOrStarredExpressionList AugmentedAssignOp TestExpressionList => CreateAugmentedAssignStatement($1, $2, $3, @2)
    TestOrStarredExpressionList '=' AssignStatementRhs =>:
        let list = Sequence.Prepend($1, $3.Item1)
        $$ = CreateAssignStatement(list, $3.Item2, @@)
    TestOrStarredExpressionList ':' TypeExpression '=' TestExpression =>:
        let isSimple = CheckAnnAssignStatementTarget($1, @1)
        $$ = Statement.NewAnnAssign($1, $3, $5, isSimple, @@)
    TestOrStarredExpressionList ':' TypeExpression =>:
        let isSimple = CheckAnnAssignStatementTarget($1, @1)
        $$ = Statement.NewAnnAssign($1, $3, None, isSimple, @@)
    TestOrStarredExpressionList => Statement.NewExpr($1, @@)
    TestOrStarredExpressionList '++' =>:
        _validator.SetUsage($1, ExpressionUsage.Store)
        $$ = Statement.NewIncrement($1, @@)
    TestOrStarredExpressionList '--' =>:
        _validator.SetUsage($1, ExpressionUsage.Store)
        $$ = Statement.NewDecrement($1, @@)

AssignStatementRhs as ([Expression], Expression):
    YieldExpression => (default([Expression]), $1)
    TestOrStarredExpressionList => (default([Expression]), $1)
    TestOrStarredExpressionList '=' AssignStatementRhs =>:
        $$ = (Sequence.Append($3.Item1, $1), $3.Item2)

ExpressionList as Expression:
    ExpressionListNoTrailingComma => CheckExpressionList(False, @@, $1, ExpressionUsage.Load)
    ExpressionListNoTrailingComma ',' => CheckExpressionList(True, @@, $1, ExpressionUsage.Load)

ExpressionListNoTrailingComma as [Expression]:
    ExpressionListItem => Sequence.Create($1)
    ExpressionListNoTrailingComma ',' ExpressionListItem => Sequence.Append($1, $3)

ExpressionListItem as Expression:
    Expression => $1
    StarredExpression => $1

ExpressionPairListNoTrailingComma as ([Expression], [Expression]):
    ExpressionPair => (Sequence.Create($1.Item1), Sequence.Create($1.Item2))
    ExpressionPairListNoTrailingComma ',' ExpressionPair => (Sequence.Append($1.Item1, $3.Item1), Sequence.Append($1.Item2, $3.Item2))

ExpressionPair as (Expression, Expression):
    TestExpression ':' TestExpression => ($1, $3)
    '**' Expression => (default(Expression), $2)

TestOrStarredExpressionList as Expression:
    TestOrStarredExpressionListNoTrailingComma => CheckExpressionList(False, @@, $1, ExpressionUsage.Load)
    TestOrStarredExpressionListNoTrailingComma ',' => CheckExpressionList(True, @@, $1, ExpressionUsage.Load)

TestOrStarredExpressionListNoTrailingComma as [Expression]:
    TestOrStarredExpression => Sequence.Create($1)
    TestOrStarredExpressionListNoTrailingComma ',' TestOrStarredExpression => Sequence.Append($1, $3)

TestOrStarredExpression as Expression:
    TestExpression => $1
    StarredExpression => $1

TestExpressionList as Expression:
    TestExpressionListNoTrailingComma => CheckExpressionList(False, @@, $1, ExpressionUsage.Load)
    TestExpressionListNoTrailingComma ',' => CheckExpressionList(True, @@, $1, ExpressionUsage.Load)

TestExpressionListNoTrailingComma as [Expression]:
    TestExpression => Sequence.Create($1)
    TestExpressionListNoTrailingComma ',' TestExpression => Sequence.Append($1, $3)

TestExpression as Expression:
    OrTestExpression => $1
    OrTestExpression 'if' OrTestExpression 'else' TestExpression => Expression.NewIfExpr($3, $1, $5, @@)
    LambdaExpression => $1

TestExpressionNoConditional as Expression:
    OrTestExpression => $1
    LambdaExpressionNoConditional => $1

LambdaExpression as Expression:
    'lambda' LambdaParameterList ':' TestExpression => Expression.NewLambda($2, $4, @@)

LambdaExpressionNoConditional as Expression:
    'lambda' LambdaParameterList ':' TestExpressionNoConditional => Expression.NewLambda($2, $4, @@)

LambdaParameterList as ParameterList:
    LambdaParameters =>:
        var pos = $1.Item1
        var xtra = $1.Item2
        var kw = xtra.Item2
        pos = CheckPositionalDefaults(pos)
        $$ = ParameterList.New(pos.Item1, pos.Item2, kw.Item1, kw.Item2, xtra.Item1, xtra.Item3, @@)
        _validator.CheckParameterCount($$)

LambdaParameters as (([Parameter], [Expression]), (Parameter?, ([Parameter], [Expression]), Parameter?)):
    LambdaPositionalParameters ',' LambdaExtraParameters => ($1, $3)
    LambdaPositionalParameters ',' =>:
        var kw = (default([Parameter]), default([Expression]))
        var xtra = (default(Parameter), kw, default(Parameter))
        $$ = ($1, xtra)
    LambdaPositionalParameters =>:
        var kw = (default([Parameter]), default([Expression]))
        var xtra = (default(Parameter), kw, default(Parameter))
        $$ = ($1, xtra)
    LambdaExtraParameters =>:
        var pos = (default([Parameter]), default([Expression]))
        $$ = (pos, $1)
    =>:
        var pos = (default([Parameter]), default([Expression]))
        var kw = (default([Parameter]), default([Expression]))
        var xtra = (default(Parameter), kw, default(Parameter))
        $$ = (pos, xtra)

LambdaPositionalParameters as ([Parameter], [Expression]):
    LambdaParameter => (Sequence.Create($1), Sequence.Create(default(Expression)))
    LambdaParameter '=' TestExpression => (Sequence.Create($1), Sequence.Create($3))
    LambdaPositionalParameters ',' LambdaParameter => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, default(Expression)))
    LambdaPositionalParameters ',' LambdaParameter '=' TestExpression => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, $5))

LambdaKeywordParameters as ([Parameter], [Expression]):
    ',' LambdaParameter => (Sequence.Create($2), Sequence.Create(default(Expression)))
    ',' LambdaParameter '=' TestExpression => (Sequence.Create($2), Sequence.Create($4))
    LambdaKeywordParameters ',' LambdaParameter => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, default(Expression)))
    LambdaKeywordParameters ',' LambdaParameter '=' TestExpression => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, $5))

LambdaExtraParameters as (Parameter?, ([Parameter], [Expression]), Parameter?):
    '*' LambdaParameter LambdaKeywordParameters ',' '**' LambdaParameter => ($2, $3, $6)
    '*' LambdaParameter LambdaKeywordParameters => ($2, $3, default(Parameter))
    '*' LambdaParameter ',' '**' LambdaParameter => ($2, (default([Parameter]), default([Expression])), $5)
    '*' LambdaParameter => ($2, (default([Parameter]), default([Expression])), default(Parameter))
    '*' LambdaKeywordParameters ',' '**' LambdaParameter => (default(Parameter), $2, $5)
    '*' LambdaKeywordParameters => (default(Parameter), $2, default(Parameter))
    '*' ',' '**' LambdaParameter => (default(Parameter), (default([Parameter]), default([Expression])), $4)
    '**' LambdaParameter => (default(Parameter), (default([Parameter]), default([Expression])), $2)

LambdaParameter as Parameter:
    name => CreateParameter($1, None, @@)

FunctionParameterList as ParameterList:
    FunctionParameters =>:
        var pos = $1.Item1
        var xtra = $1.Item2
        var kw = xtra.Item2
        pos = CheckPositionalDefaults(pos)
        $$ = ParameterList.New(pos.Item1, pos.Item2, kw.Item1, kw.Item2, xtra.Item1, xtra.Item3, @@)
        _validator.CheckParameterCount($$)

FunctionParameters as (([Parameter], [Expression]), (Parameter?, ([Parameter], [Expression]), Parameter?)):
    FunctionPositionalParameters ',' FunctionExtraParameters => ($1, $3)
    FunctionPositionalParameters ',' =>:
        var kw = (default([Parameter]), default([Expression]))
        var xtra = (default(Parameter), kw, default(Parameter))
        $$ = ($1, xtra)
    FunctionPositionalParameters =>:
        var kw = (default([Parameter]), default([Expression]))
        var xtra = (default(Parameter), kw, default(Parameter))
        $$ = ($1, xtra)
    FunctionExtraParameters =>:
        var pos = (default([Parameter]), default([Expression]))
        $$ = (pos, $1)
    =>:
        var pos = (default([Parameter]), default([Expression]))
        var kw = (default([Parameter]), default([Expression]))
        var xtra = (default(Parameter), kw, default(Parameter))
        $$ = (pos, xtra)

FunctionPositionalParameters as ([Parameter], [Expression]):
    FunctionParameter => (Sequence.Create($1), Sequence.Create(default(Expression)))
    FunctionParameter '=' TestExpression => (Sequence.Create($1), Sequence.Create($3))
    FunctionPositionalParameters ',' FunctionParameter => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, default(Expression)))
    FunctionPositionalParameters ',' FunctionParameter '=' TestExpression => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, $5))

FunctionKeywordParameters as ([Parameter], [Expression]):
    ',' FunctionParameter => (Sequence.Create($2), Sequence.Create(default(Expression)))
    ',' FunctionParameter '=' TestExpression => (Sequence.Create($2), Sequence.Create($4))
    FunctionKeywordParameters ',' FunctionParameter => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, default(Expression)))
    FunctionKeywordParameters ',' FunctionParameter '=' TestExpression => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, $5))

FunctionExtraParameters as (Parameter?, ([Parameter], [Expression]), Parameter?):
    '*' FunctionParameter FunctionKeywordParameters ',' '**' FunctionParameter => ($2, $3, $6)
    '*' FunctionParameter FunctionKeywordParameters => ($2, $3, default(Parameter))
    '*' FunctionParameter ',' '**' FunctionParameter => ($2, (default([Parameter]), default([Expression])), $5)
    '*' FunctionParameter => ($2, (default([Parameter]), default([Expression])), default(Parameter))
    '*' FunctionKeywordParameters ',' '**' FunctionParameter => (default(Parameter), $2, $5)
    '*' FunctionKeywordParameters => (default(Parameter), $2, default(Parameter))
    '*' ',' '**' FunctionParameter => (default(Parameter), (default([Parameter]), default([Expression])), $4)
    '**' FunctionParameter => (default(Parameter), (default([Parameter]), default([Expression])), $2)

FunctionParameter as Parameter:
    name => CreateParameter($1, None, @@)
    name ':' TypeExpression => CreateParameter($1, $3, @@)

OptionalCallArgumentList as ([Expression], [KeywordArgument]):
    => (default([Expression]), default([KeywordArgument]))
    CallArgumentList => $1

CallArgumentList as ([Expression], [KeywordArgument]):
    '(' ')' =>:
        $$ = (default([Expression]), default([KeywordArgument]))
    '(' TestExpression ComprehensionForSeries ')' =>:
        var g = Expression.NewGenerator($2, $3, new SourceContext(@1.Begin, @4.End))
        $$ = (Sequence.Create(g), default([KeywordArgument]))
    '(' CallArgumentListNoTrailingComma ','? ')' =>:
        _validator.CheckArgumentCount($2.Item1, $2.Item2, @2)
        $$ = $2

CallArgumentListNoTrailingComma as ([Expression], [KeywordArgument]):
    TestExpression => (Sequence.Create($1), default([KeywordArgument]))
    name '=' TestExpression =>:
        _validator.CheckForbiddenName($1, True)
        var kw = KeywordArgument.New($3, $1, @@)
        $$ = (default([Expression]), Sequence.Create(kw))
    '**' TestExpression =>:
        var kw = KeywordArgument.New($2, None, @@)
        $$ = (default([Expression]), Sequence.Create(kw))
    '*' TestExpression =>:
        var star = Expression.NewStarred($2, ExpressionUsage.Load, @@)
        $$ = (Sequence.Create(star), default([KeywordArgument]))
    CallArgumentListNoTrailingComma ',' TestExpression =>:
        CheckCallArgumentOrder($1, @3, False)
        $$ = (Sequence.Append($1.Item1, $3), $1.Item2)
    CallArgumentListNoTrailingComma ',' name '=' TestExpression =>:
        _validator.CheckForbiddenName($3, True)
        var kw = KeywordArgument.New($5, $3, SourceContext.New(@3.Begin, @5.End))
        $$ = ($1.Item1, Sequence.Append($1.Item2, kw))
    CallArgumentListNoTrailingComma ',' '**' TestExpression =>:
        var kw = KeywordArgument.New($4, None, SourceContext.New(@3.Begin, @4.End))
        $$ = ($1.Item1, Sequence.Append($1.Item2, kw))
    CallArgumentListNoTrailingComma ',' '*' TestExpression =>:
        CheckCallArgumentOrder($1, @3, True)
        var star = Expression.NewStarred($4, ExpressionUsage.Load, @@)
        $$ = (Sequence.Append($1.Item1, star), $1.Item2)

Indexer as SequenceSlice:
    TestExpression => SequenceSlice.NewIndexer($1)

Slice as SequenceSlice:
    ':' => SequenceSlice.NewRange(None, None, None, @@)
    ':' ':' => SequenceSlice.NewRange(None, None, None, @@)
    TestExpression ':' => SequenceSlice.NewRange($1, None, None, @@)
    TestExpression ':' ':' => SequenceSlice.NewRange($1, None, None, @@)
    ':' TestExpression => SequenceSlice.NewRange(None, $2, None, @@)
    ':' TestExpression ':' => SequenceSlice.NewRange(None, $2, None, @@)
    ':' ':' TestExpression => SequenceSlice.NewRange(None, None, $3, @@)
    TestExpression ':' TestExpression => SequenceSlice.NewRange($1, $3, None, @@)
    TestExpression ':' TestExpression ':' => SequenceSlice.NewRange($1, $3, None, @@)
    TestExpression ':' ':' TestExpression => SequenceSlice.NewRange($1, None, $4, @@)
    ':' TestExpression ':' TestExpression => SequenceSlice.NewRange(None, $2, $4, @@)
    TestExpression ':' TestExpression ':' TestExpression => SequenceSlice.NewRange($1, $3, $5, @@)

Subscript as SequenceSlice:
    Indexer => $1
    Slice => $1

SubscriptList as [SequenceSlice]:
    Subscript => Sequence.Create($1)
    SubscriptList ',' Subscript => Sequence.Append($1, $3)

OrTestExpression as Expression:
    AndTestExpression => $1
    AndTestExpression 'or' OrTestOperands => Expression.NewBoolean(BooleanOp.LogicalOr, Sequence.Prepend($1, $3), @@)

OrTestOperands as [Expression]:
    AndTestExpression => Sequence.Create($1)
    OrTestOperands 'or' AndTestExpression => Sequence.Append($1, $3)

AndTestExpression as Expression:
    NotTestExpression => $1
    NotTestExpression 'and' AndTestOperands => Expression.NewBoolean(BooleanOp.LogicalAnd, Sequence.Prepend($1, $3), @@)

AndTestOperands as [Expression]:
    NotTestExpression => Sequence.Create($1)
    AndTestOperands 'and' NotTestExpression => Sequence.Append($1, $3)

NotTestExpression as Expression:
    'not' NotTestExpression => Expression.NewUnary(UnaryOp.LogicalNot, $2, @@)
    ComparisonExpression => $1

ComparisonExpression as Expression:
    Expression => $1
    Expression ComparandList => Expression.NewComparison($1, $2.Item1, $2.Item2, @@)

ComparandList as ([ComparisonOp], [Expression]):
    ComparisonOp Expression => (Sequence.Create($1), Sequence.Create($2))
    ComparandList ComparisonOp Expression => (Sequence.Append($1.Item1, $2), Sequence.Append($1.Item2, $3))

ComparisonOp as ComparisonOp:
    '<' => ComparisonOp.LessThan
    '<=' => ComparisonOp.LessEqual
    '>' => ComparisonOp.GreaterThan
    '>=' => ComparisonOp.GreaterEqual
    '==' => ComparisonOp.EqualTo
    '!=' => ComparisonOp.NotEqualTo
    'is' => ComparisonOp.Is
    'is' 'not' => ComparisonOp.IsNot
    'in' => ComparisonOp.In
    'not' 'in' => ComparisonOp.NotIn

StarredExpression as Expression:
    '*' Expression => Expression.NewStarred($2, ExpressionUsage.Load, @@)

Expression as Expression:
    BitwiseXorExpression => $1
    Expression '|' BitwiseXorExpression => Expression.NewBinary($1, BinaryOp.BitwiseOr, $3, @@)

BitwiseXorExpression as Expression:
    BitwiseAndExpression => $1
    BitwiseXorExpression '^' BitwiseAndExpression => Expression.NewBinary($1, BinaryOp.BitwiseXor, $3, @@)

BitwiseAndExpression as Expression:
    ShiftExpression => $1
    BitwiseAndExpression '&' ShiftExpression => Expression.NewBinary($1, BinaryOp.BitwiseAnd, $3, @@)

ShiftExpression as Expression:
    ArithmeticExpression => $1
    ShiftExpression '<<' ArithmeticExpression => Expression.NewBinary($1, BinaryOp.LeftShift, $3, @@)
    ShiftExpression '>>' ArithmeticExpression => Expression.NewBinary($1, BinaryOp.RightShift, $3, @@)

ArithmeticExpression as Expression:
    TermExpression => $1
    ArithmeticExpression '+' TermExpression => Expression.NewBinary($1, BinaryOp.Add, $3, @@)
    ArithmeticExpression '-' TermExpression => Expression.NewBinary($1, BinaryOp.Subtract, $3, @@)

TermExpression as Expression:
    FactorExpression => $1
    TermExpression '*' FactorExpression => Expression.NewBinary($1, BinaryOp.Multiply, $3, @@)
    TermExpression '@' FactorExpression => Expression.NewBinary($1, BinaryOp.MatrixMultiply, $3, @@)
    TermExpression '//' FactorExpression => Expression.NewBinary($1, BinaryOp.FloorDivide, $3, @@)
    TermExpression '/' FactorExpression => Expression.NewBinary($1, BinaryOp.Divide, $3, @@)
    TermExpression '%' FactorExpression => Expression.NewBinary($1, BinaryOp.Modulo, $3, @@)

FactorExpression as Expression:
    '+' FactorExpression => Expression.NewUnary(UnaryOp.Positive, $2, @@)
    '-' FactorExpression => Expression.NewUnary(UnaryOp.Negative, $2, @@)
    '~' FactorExpression => Expression.NewUnary(UnaryOp.BitwiseNot, $2, @@)
    PowerExpression => $1

PowerExpression as Expression:
    AtomicExpression => $1
    AtomicExpression '**' FactorExpression => Expression.NewBinary($1, BinaryOp.Power, $3, @@)

AtomicExpression as Expression:
    TypeCheckExpression => $1
    'await' TypeCheckExpression => Expression.NewAwait($2, @@)

TypeCheckExpression as Expression:
    PostfixExpression => $1
    TypeCheckExpression ':?' TypeExpression => Expression.NewIsInstanceOf($1, $3, @@)
    TypeCheckExpression ':?>' TypeExpression => Expression.NewAsInstanceOf($1, $3, @@)

PostfixExpression as Expression:
    PrimaryExpression => $1
    PostfixExpression CallArgumentList =>:
        _validator.CheckArgumentCount($2.Item1, $2.Item2, @2)
        $$ = Expression.NewCall($1, $2.Item1, $2.Item2, @@)
    PostfixExpression '[' SubscriptList ']' =>:
        var n = CheckSubscriptList($3, False, @3)
        $$ = Expression.NewSubscript($1, n, ExpressionUsage.Load, @@)
    PostfixExpression '[' SubscriptList ',' ']' =>:
        var n = CheckSubscriptList($3, True, SourceContext.New(@3.Begin, @4.End))
        $$ = Expression.NewSubscript($1, n, ExpressionUsage.Load, @@)
    PostfixExpression '.' name => Expression.NewAccess($1, $3, ExpressionUsage.Load, @@)

PrimaryExpression as Expression:
    '(' YieldExpression ')' => $2
    '(' TestOrStarredExpression ')' => $2

    '(' ')' => Expression.NewTuple(default([Expression]), ExpressionUsage.Load, @@)
    '(' TestOrStarredExpression ',' TestOrStarredExpressionListNoTrailingComma ','? ')' => Expression.NewTuple(Sequence.Prepend($2, $4), ExpressionUsage.Load, @@)
    '(' TestExpression ComprehensionForSeries ')' => Expression.NewGenerator($2, $3, @@)

    '[' ']' => Expression.NewList(default([Expression]), ExpressionUsage.Load, @@)
    '[' TestOrStarredExpressionListNoTrailingComma ','? ']' => Expression.NewList($2, ExpressionUsage.Load, @@)
    '[' TestExpression ComprehensionForSeries ']' => Expression.NewListComp($2, $3, @@)

    '{' '}' => Expression.NewDict(default([Expression]), default([Expression]), @@)
    '{' ExpressionPairListNoTrailingComma ','? '}' => Expression.NewDict($2.Item1, $2.Item2, @@)
    '{' TestExpression ':' TestExpression ComprehensionForSeries '}' => Expression.NewDictComp($2, $4, $5, @@)

    '{' TestOrStarredExpressionListNoTrailingComma ','? '}' => Expression.NewSet($2, @@)
    '{' TestExpression ComprehensionForSeries '}' => Expression.NewSetComp($2, $3, @@)

    name => Expression.NewNameReference($1, ExpressionUsage.Load, @@)
    NumberLiteral => Expression.NewNumber($1, @@)
    StringLiteralList => ConcatStrings($1)
    '...' => Expression.NewEllipsis(@@)
    'None' => Expression.NewNamedConstant(NamedConstant.`None`, @@)
    'True' => Expression.NewNamedConstant(NamedConstant.`True`, @@)
    'False' => Expression.NewNamedConstant(NamedConstant.`False`, @@)

    # Extensions for parser generator implementation.
    'this' => Expression.NewThisRef(@@)
    'base' => Expression.NewBaseRef(@@)
    BuiltinTypeCode => Expression.NewTypeRef($1, @@)
    '$$' => Expression.NewResultValueRef(ExpressionUsage.Load, @@)
    '@@' => Expression.NewResultContextRef(ExpressionUsage.Load, @@)
    StackSlotValueRef => Expression.NewSlotValueRef(ExtractIntOutOfNumberLiteral($1, @1), ExpressionUsage.Load, @@)
    StackSlotContextRef => Expression.NewSlotContextRef(ExtractIntOutOfNumberLiteral($1, @1), ExpressionUsage.Load, @@)
    'new' TypeExpression CallArgumentList =>:
        _validator.CheckArgumentCount($3.Item1, $3.Item2, @3)
        $$ = Expression.NewNew($2, $3.Item1, $3.Item2, @@)
    'default' '(' TypeExpression ')' => Expression.NewDefault($3, @@)
    'typeof' '(' TypeExpression ')' => Expression.NewTypeOf($3, @@)
    'nameof' '(' Expression ')' => Expression.NewNameOf($3, @@)

ComprehensionForSeries as [Comprehension]:
    ComprehensionFor => Sequence.Create($1)
    ComprehensionForSeries ComprehensionFor => Sequence.Append($1, $2)

ComprehensionFor as Comprehension:
    'for' ExpressionList 'in' OrTestExpression ComprehensionIfNoneableSeries =>:
        _validator.SetUsage($2, ExpressionUsage.Store)
        $$ = Comprehension.New($2, $4, $5, False, @@)
    'async' 'for' ExpressionList 'in' OrTestExpression ComprehensionIfNoneableSeries =>:
        _validator.SetUsage($3, ExpressionUsage.Store)
        $$ = Comprehension.New($3, $5, $6, True, @@)

ComprehensionIfNoneableSeries as [Expression]:
    => default([Expression])
    ComprehensionIfNoneableSeries ComprehensionIf => Sequence.Append($1, $2)

ComprehensionIf as Expression:
    'if' TestExpressionNoConditional => $2

YieldExpression as Expression:
    'yield' 'from' TestExpression => Expression.NewYieldFrom($3, @@)
    'yield' TestExpressionList => Expression.NewYield($2, @@)
    'yield' => Expression.NewYield(None, @@)

StringLiteralList as [(Constant, SourceContext)]:
    StringLiteral => Sequence.Create(($1, @1))
    QuoteLiteral => Sequence.Create(($1, @1))
    StringLiteralList StringLiteral => Sequence.Append($1, ($2, @2))
    StringLiteralList QuoteLiteral => Sequence.Append($1, ($2, @2))

AugmentedAssignOp as BinaryOp:
    '+=' => BinaryOp.Add
    '-=' => BinaryOp.Subtract
    '*=' => BinaryOp.Multiply
    '@=' => BinaryOp.MatrixMultiply
    '//=' => BinaryOp.FloorDivide
    '/=' => BinaryOp.Divide
    '%=' => BinaryOp.Modulo
    '**=' => BinaryOp.Power
    '<<=' => BinaryOp.LeftShift
    '>>=' => BinaryOp.RightShift
    '&=' => BinaryOp.BitwiseAnd
    '^=' => BinaryOp.BitwiseXor
    '|=' => BinaryOp.BitwiseOr

ModuleSpecifier as (DottedName?, int?):
    DotCounter DottedName => ($2, $1 :?> int?)
    DottedName => ($1, default(int?))
    DotCounter => (default(DottedName), $1 :?> int?)

DotCounter as int:
    '.' => 1
    '...' => 3
    DotCounter '.' => $1 + 1
    DotCounter '...' => $1 + 3

name as Name:
    Name => $1
    '`' Name '`' => $2
    '`' 'and' '`' => LexicalAnalysis.Name.New("and", @2)
    '`' 'as' '`' => LexicalAnalysis.Name.New("as", @2)
    '`' 'assert' '`' => LexicalAnalysis.Name.New("assert", @2)
    '`' 'async' '`' => LexicalAnalysis.Name.New("async", @2)
    '`' 'attributes' '`' => LexicalAnalysis.Name.New("attributes", @2)
    '`' 'await' '`' => LexicalAnalysis.Name.New("await", @2)
    '`' 'base' '`' => LexicalAnalysis.Name.New("base", @2)
    '`' 'bool' '`' => LexicalAnalysis.Name.New("bool", @2)
    '`' 'break' '`' => LexicalAnalysis.Name.New("break", @2)
    '`' 'byte' '`' => LexicalAnalysis.Name.New("byte", @2)
    '`' 'char' '`' => LexicalAnalysis.Name.New("char", @2)
    '`' 'char16' '`' => LexicalAnalysis.Name.New("char16", @2)
    '`' 'char32' '`' => LexicalAnalysis.Name.New("char32", @2)
    '`' 'char8' '`' => LexicalAnalysis.Name.New("char8", @2)
    '`' 'class' '`' => LexicalAnalysis.Name.New("class", @2)
    '`' 'continue' '`' => LexicalAnalysis.Name.New("continue", @2)
    '`' 'decimal' '`' => LexicalAnalysis.Name.New("decimal", @2)
    '`' 'def' '`' => LexicalAnalysis.Name.New("def", @2)
    '`' 'default' '`' => LexicalAnalysis.Name.New("default", @2)
    '`' 'del' '`' => LexicalAnalysis.Name.New("del", @2)
    '`' 'double' '`' => LexicalAnalysis.Name.New("double", @2)
    '`' 'dynamic' '`' => LexicalAnalysis.Name.New("dynamic", @2)
    '`' 'elif' '`' => LexicalAnalysis.Name.New("elif", @2)
    '`' 'else' '`' => LexicalAnalysis.Name.New("else", @2)
    '`' 'except' '`' => LexicalAnalysis.Name.New("except", @2)
    '`' 'False' '`' => LexicalAnalysis.Name.New("False", @2)
    '`' 'finally' '`' => LexicalAnalysis.Name.New("finally", @2)
    '`' 'float' '`' => LexicalAnalysis.Name.New("float", @2)
    '`' 'float32' '`' => LexicalAnalysis.Name.New("float32", @2)
    '`' 'float64' '`' => LexicalAnalysis.Name.New("float64", @2)
    '`' 'for' '`' => LexicalAnalysis.Name.New("for", @2)
    '`' 'from' '`' => LexicalAnalysis.Name.New("from", @2)
    '`' 'global' '`' => LexicalAnalysis.Name.New("global", @2)
    '`' 'grammar' '`' => LexicalAnalysis.Name.New("grammar", @2)
    '`' 'if' '`' => LexicalAnalysis.Name.New("if", @2)
    '`' 'import' '`' => LexicalAnalysis.Name.New("import", @2)
    '`' 'in' '`' => LexicalAnalysis.Name.New("in", @2)
    '`' 'int' '`' => LexicalAnalysis.Name.New("int", @2)
    '`' 'int16' '`' => LexicalAnalysis.Name.New("int16", @2)
    '`' 'int32' '`' => LexicalAnalysis.Name.New("int32", @2)
    '`' 'int64' '`' => LexicalAnalysis.Name.New("int64", @2)
    '`' 'int8' '`' => LexicalAnalysis.Name.New("int8", @2)
    '`' 'intptr_t' '`' => LexicalAnalysis.Name.New("intptr_t", @2)
    '`' 'is' '`' => LexicalAnalysis.Name.New("is", @2)
    '`' 'lambda' '`' => LexicalAnalysis.Name.New("lambda", @2)
    '`' 'let' '`' => LexicalAnalysis.Name.New("let", @2)
    '`' 'long' '`' => LexicalAnalysis.Name.New("long", @2)
    '`' 'new' '`' => LexicalAnalysis.Name.New("new", @2)
    '`' 'None' '`' => LexicalAnalysis.Name.New("None", @2)
    '`' 'nonlocal' '`' => LexicalAnalysis.Name.New("nonlocal", @2)
    '`' 'not' '`' => LexicalAnalysis.Name.New("not", @2)
    '`' 'object' '`' => LexicalAnalysis.Name.New("object", @2)
    '`' 'of' '`' => LexicalAnalysis.Name.New("of", @2)
    '`' 'one' '`' => LexicalAnalysis.Name.New("one", @2)
    '`' 'or' '`' => LexicalAnalysis.Name.New("or", @2)
    '`' 'pass' '`' => LexicalAnalysis.Name.New("pass", @2)
    '`' 'ptrdiff_t' '`' => LexicalAnalysis.Name.New("ptrdiff_t", @2)
    '`' 'raise' '`' => LexicalAnalysis.Name.New("raise", @2)
    '`' 'return' '`' => LexicalAnalysis.Name.New("return", @2)
    '`' 'reversed' '`' => LexicalAnalysis.Name.New("reversed", @2)
    '`' 'sbyte' '`' => LexicalAnalysis.Name.New("sbyte", @2)
    '`' 'short' '`' => LexicalAnalysis.Name.New("short", @2)
    '`' 'size_t' '`' => LexicalAnalysis.Name.New("size_t", @2)
    '`' 'ssize_t' '`' => LexicalAnalysis.Name.New("ssize_t", @2)
    '`' 'string' '`' => LexicalAnalysis.Name.New("string", @2)
    '`' 'this' '`' => LexicalAnalysis.Name.New("this", @2)
    '`' 'True' '`' => LexicalAnalysis.Name.New("True", @2)
    '`' 'try' '`' => LexicalAnalysis.Name.New("try", @2)
    '`' 'uint' '`' => LexicalAnalysis.Name.New("uint", @2)
    '`' 'uint16' '`' => LexicalAnalysis.Name.New("uint16", @2)
    '`' 'uint32' '`' => LexicalAnalysis.Name.New("uint32", @2)
    '`' 'uint64' '`' => LexicalAnalysis.Name.New("uint64", @2)
    '`' 'uint8' '`' => LexicalAnalysis.Name.New("uint8", @2)
    '`' 'uintptr_t' '`' => LexicalAnalysis.Name.New("uintptr_t", @2)
    '`' 'ulong' '`' => LexicalAnalysis.Name.New("ulong", @2)
    '`' 'unit' '`' => LexicalAnalysis.Name.New("unit", @2)
    '`' 'ushort' '`' => LexicalAnalysis.Name.New("ushort", @2)
    '`' 'var' '`' => LexicalAnalysis.Name.New("var", @2)
    '`' 'while' '`' => LexicalAnalysis.Name.New("while", @2)
    '`' 'with' '`' => LexicalAnalysis.Name.New("with", @2)
    '`' 'yield' '`' => LexicalAnalysis.Name.New("yield", @2)

NameList as [Name]:
    name => Sequence.Create($1)
    NameList ',' name => Sequence.Append($1, $3)

NameAs as ImportBinding:
    name =>:
        _validator.CheckForbiddenName($1)
        $$ = ImportBinding.New(DottedName.New(Sequence.Create($1), @1), None, @@)
    name 'as' name =>:
        _validator.CheckForbiddenName($3)
        $$ = ImportBinding.New(DottedName.New(Sequence.Create($1), @1), $3, @@)

NameAsList as [ImportBinding]:
    NameAs => Sequence.Create($1)
    NameAsList ',' NameAs => Sequence.Append($1, $3)

DottedNameAs as ImportBinding:
    name =>:
        _validator.CheckForbiddenName($1)
        $$ = ImportBinding.New(DottedName.New(Sequence.Create($1), @@), None, @@)
    name 'as' name =>:
        _validator.CheckForbiddenName($3)
        $$ = ImportBinding.New(DottedName.New(Sequence.Create($1), @@), $3, @@)
    name '.' DottedName =>:
        $$ = ImportBinding.New(DottedName.New(Sequence.Prepend($1, $3.Items), @@), None, @@)
    name '.' DottedName 'as' name =>:
        _validator.CheckForbiddenName($5)
        $$ = ImportBinding.New(DottedName.New(Sequence.Prepend($1, $3.Items), @@), $5, @@)

DottedNameAsList as [ImportBinding]:
    DottedNameAs => Sequence.Create($1)
    DottedNameAsList ',' DottedNameAs => Sequence.Append($1, $3)

DottedName as DottedName:
    name => DottedName.New(Sequence.Create($1), @@)
    DottedName '.' name => DottedName.New(Sequence.Append($1.Items, $3), @@)

DottedNameExpression as Expression:
    name => Expression.NewNameReference($1, ExpressionUsage.Load, @@)
    DottedNameExpression '.' name => Expression.NewAccess($1, $3, ExpressionUsage.Load, @@)

ProgramModule as ProgramDescription:
    => ProgramDescription.NewModule(default([Statement]), @@)
    ProgramModule NewLine => $1
    ProgramModule SimpleStatement NewLine => ProgramDescription.NewModule(Sequence.Concat($1.AsModule.Body, $2), @@)
    ProgramModule CompoundStatement => ProgramDescription.NewModule(Sequence.Append($1.AsModule.Body, $2), @@)

InteractiveSegment as ProgramDescription:
    => ProgramDescription.NewSegment(default([Statement]), @@)
    SimpleStatement => ProgramDescription.NewSegment($1, @@)
    CompoundStatement => ProgramDescription.NewSegment(Sequence.Create($1), @@)

SingleExpression as ProgramDescription:
    TestExpressionList => ProgramDescription.NewExpression($1, @@)
    SingleExpression NewLine => $1

BuiltinTypeCode as BuiltinTypeCode:
    'int8' => BuiltinTypeCode.Int8
    'int16' => BuiltinTypeCode.Int16
    'int32' => BuiltinTypeCode.Int32
    'int64' => BuiltinTypeCode.Int64

    'uint8' => BuiltinTypeCode.UInt8
    'uint16' => BuiltinTypeCode.UInt16
    'uint32' => BuiltinTypeCode.UInt32
    'uint64' => BuiltinTypeCode.UInt64

    'float32' => BuiltinTypeCode.Float32
    'float64' => BuiltinTypeCode.Float64

    'char8' => BuiltinTypeCode.Char8
    'char16' => BuiltinTypeCode.Char16
    'char32' => BuiltinTypeCode.Char32

    'sbyte' => BuiltinTypeCode.SByte
    'short' => BuiltinTypeCode.Short
    'int' => BuiltinTypeCode.Int
    'long' => BuiltinTypeCode.Long

    'byte' => BuiltinTypeCode.Byte
    'ushort' => BuiltinTypeCode.UShort
    'uint' => BuiltinTypeCode.UInt
    'ulong' => BuiltinTypeCode.ULong

    'intptr_t' => BuiltinTypeCode.IntPtrT
    'uintptr_t' => BuiltinTypeCode.UIntPtrT
    'size_t' => BuiltinTypeCode.SizeT
    'ssize_t' => BuiltinTypeCode.SSizeT
    'ptrdiff_t' => BuiltinTypeCode.PtrDiffT

    'float' => BuiltinTypeCode.Float
    'double' => BuiltinTypeCode.Double
    'decimal' => BuiltinTypeCode.Decimal

    'bool' => BuiltinTypeCode.Bool
    'char' => BuiltinTypeCode.Char

    'string' => BuiltinTypeCode.String
    'object' => BuiltinTypeCode.Object
    'dynamic' => BuiltinTypeCode.Dynamic

    'unit' => BuiltinTypeCode.Unit

PrimaryTypeExpression as TypeExpression:
    BuiltinTypeCode => TypeExpression.NewBuiltin($1, @@)
    name => TypeExpression.NewNameReference($1, @@)
    '[' TypeExpression ']' => TypeExpression.NewList($2, @@)
    '{' TypeExpression '}' => TypeExpression.NewSet($2, @@)
    '{' name ':' TypeExpression '}' => TypeExpression.NewMap(TypeExpression.NewNameReference($2, @2), $4, @@)
    '{' TypeExpression ':' TypeExpression '}' => TypeExpression.NewMap($2, $4, @@)
    '(' TypeExpression ')' => $2
    '(' ')' => TypeExpression.NewTuple(default([TypeExpression]), False, @@)
    '(' TypeExpressions ',' ')' => TypeExpression.NewTuple($2, False, @@)
    '(' TypeExpressions ',' TypeExpression ')' => TypeExpression.NewTuple(Sequence.Append($2, $4), False, @@)
    '{' '}' => TypeExpression.NewTuple(default([TypeExpression]), True, @@)
    '{' TypeExpressions ',' '}' => TypeExpression.NewTuple($2, True, @@)
    '{' TypeExpressions ',' TypeExpression '}' => TypeExpression.NewTuple(Sequence.Append($2, $4), True, @@)
    '(' NameTypePairs ',' ')' => TypeExpression.NewRecord($2.Item1, $2.Item2, False, @@)
    '(' NameTypePairs ',' name ':' TypeExpression ')' => TypeExpression.NewRecord(Sequence.Append($2.Item1, $4), Sequence.Append($2.Item2, $6), False, @@)
    '{' NameTypePairs ',' '}' => TypeExpression.NewRecord($2.Item1, $2.Item2, True, @@)
    '{' NameTypePairs ',' name ':' TypeExpression '}' => TypeExpression.NewRecord(Sequence.Append($2.Item1, $4), Sequence.Append($2.Item2, $6), True, @@)

PostfixTypeExpression as TypeExpression:
    PrimaryTypeExpression => $1
    PostfixTypeExpression '.' name => TypeExpression.NewAccess($1, $3, @@)
    PostfixTypeExpression '?' => TypeExpression.NewOptional($1, @@)
    PostfixTypeExpression '*' => TypeExpression.NewKleene($1, @@)
    PostfixTypeExpression '+' => TypeExpression.NewPositive($1, @@)
    PostfixTypeExpression '[' ']' => TypeExpression.NewArray($1, 1, @@)
    PostfixTypeExpression '[' CommaCounter ']' => TypeExpression.NewArray($1, $3 + 1, @@)
    PostfixTypeExpression '[' TypeExpressions ']' => TypeExpression.NewApplication($1, $3, @@)
    PostfixTypeExpression '[' TypeExpressions ',' ']' => TypeExpression.NewApplication($1, $3, @@)

CommaCounter as int:
    ',' => 1
    CommaCounter ',' => $1 + 1

TypeExpression as TypeExpression:
    PostfixTypeExpression => $1
    PostfixTypeExpression '->' TypeExpression => TypeExpression.NewFunction($1, $3, @@)

TypeExpressions as [TypeExpression]:
    TypeExpression => Sequence.Create($1)
    TypeExpressions ',' TypeExpression => Sequence.Append($1, $3)

NameTypePairs as ([Name], [TypeExpression]):
    name ':' TypeExpression => (Sequence.Create($1), Sequence.Create($3))
    NameTypePairs ',' name ':' TypeExpression => (Sequence.Append($1.Item1, $3), Sequence.Append($1.Item2, $5))

EnumItems as [Name]:
    name => Sequence.Create($1)
    EnumItems name => Sequence.Append($1, $2)

EnumItemList as [Name]:
    EnumItems => $1

EnumDeclarator as EnumDeclarator:
    EnumItemList NewLine => EnumDeclarator.New($1, @@)

EnumDeclarators as [EnumDeclarator]:
    EnumDeclarator => Sequence.Create($1)
    EnumDeclarators EnumDeclarator => Sequence.Append($1, $2)

EnumDeclaratorList as [EnumDeclarator]:
    EnumDeclarators => $1

EnumDeclaration as EnumDeclaration:
    EnumDeclaratorList => EnumDeclaration.New($1, False, @@)

FieldDeclarator as FieldDeclarator:
    name ':' TypeExpression => FieldDeclarator.New($1, False, $3, @@)
    name '!' ':' TypeExpression => FieldDeclarator.New($1, True, $4, @@)

FieldDeclarators as [FieldDeclarator]:
    FieldDeclarator => Sequence.Create($1)
    FieldDeclarators ',' FieldDeclarator => Sequence.Append($1, $3)

FieldDeclaratorList as [FieldDeclarator]:
    => default([FieldDeclarator])
    FieldDeclarators => $1

FieldDeclaration as FieldDeclaration:
    FieldDeclaratorList => FieldDeclaration.New($1, @@)

CaseDeclarator as CaseDeclarator:
    name NewLine => CaseDeclarator.New($1, FieldDeclaration.New(default([FieldDeclarator]), @@), @@)
    name '(' FieldDeclaration ')' NewLine => CaseDeclarator.New($1, $3, @@)

CaseDeclarators as [CaseDeclarator]:
    CaseDeclarator => Sequence.Create($1)
    CaseDeclarators CaseDeclarator => Sequence.Append($1, $2)

CaseDeclaratorList as [CaseDeclarator]:
    CaseDeclarators => $1

CaseDeclaration as CaseDeclaration:
    CaseDeclaratorList => CaseDeclaration.New($1, @@)

UnionPrefields as FieldDeclaration:
    => FieldDeclaration.New(default([FieldDeclarator]), @@)
    'attributes' '(' FieldDeclaration ')' NewLine => $3

UnionPostfields as FieldDeclaration:
    => FieldDeclaration.New(default([FieldDeclarator]), @@)
    'attributes!' '(' FieldDeclaration ')' NewLine => $3

VisitorTypeItems as [Name]:
    name => Sequence.Create($1)
    VisitorTypeItems '|' name => Sequence.Append($1, $3)

TypeDeclarator as TypeDeclarator:
    name ':' 'one' 'of' NewLine Indent EnumDeclaration Unindent => TypeDeclarator.NewEnum($1, $7, @@)
    name ':' 'reversed' 'one' 'of' NewLine Indent EnumDeclaration Unindent => TypeDeclarator.NewEnum($1, $8.WithReversed(True), @@)
    name '=' '(' FieldDeclaration ')' NewLine => TypeDeclarator.NewStruct($1, $4, False, @@)
    name '=' '{' FieldDeclaration '}' NewLine => TypeDeclarator.NewStruct($1, $4, True, @@)
    name ':' NewLine Indent CaseDeclaration UnionPrefields UnionPostfields Unindent => TypeDeclarator.NewUnion($1, $5, $6, $7, @@)

    name '.' name '(' name ':' VisitorTypeItems ',' FieldDeclaration ')' '->' TypeExpression NewLine =>:
        $$ = TypeDeclarator.NewVisitor($1, $3, $5, $7, $9, $12, @@)
    name '.' name '(' name ':' VisitorTypeItems ',' FieldDeclaration ')' NewLine =>:
        $$ = TypeDeclarator.NewVisitor($1, $3, $5, $7, $9, None, @@)
    name '.' name '(' name ':' VisitorTypeItems ')' '->' TypeExpression NewLine =>:
        $$ = TypeDeclarator.NewVisitor($1, $3, $5, $7, FieldDeclaration.New(default([FieldDeclarator]), SourceContext.New(@8.Begin, @8.Begin)), $10, @@)
    name '.' name '(' name ':' VisitorTypeItems ')' NewLine =>:
        $$ = TypeDeclarator.NewVisitor($1, $3, $5, $7, FieldDeclaration.New(default([FieldDeclarator]), SourceContext.New(@8.Begin, @8.Begin)), None, @@)

TypeDeclarators as [TypeDeclarator]:
    TypeDeclarator => Sequence.Create($1)
    TypeDeclarators TypeDeclarator => Sequence.Append($1, $2)

TypeDeclaratorList as [TypeDeclarator]:
    => default([TypeDeclarator])
    TypeDeclarators => $1

TypeDeclaration as TypeDeclaration:
    TypeDeclaratorList => TypeDeclaration.New($1, @@)

TokenDeclarator as TokenDeclarator:
    QuoteLiteral => TokenDeclarator.New(None, $1, None, @@)
    name => TokenDeclarator.New($1, None, None, @@)
    name '(' QuoteLiteral ')' => TokenDeclarator.New($1, $3, None, @@)
    name '(' StringLiteral ')' => TokenDeclarator.New($1, None, $3, @@)

TokenDeclarators as [TokenDeclarator]:
    TokenDeclarator => Sequence.Create($1)
    TokenDeclarators ',' TokenDeclarator => Sequence.Append($1, $3)

TokenDeclarationKind as TokenDeclarationKind:
    '%token' => TokenDeclarationKind.Token
    '%endmarker' => TokenDeclarationKind.EndMarker
    '%layout' => TokenDeclarationKind.LayoutMarker
    '%hidden' => TokenDeclarationKind.HiddenToken
    '%keyword' => TokenDeclarationKind.Keyword
    '%reserved' => TokenDeclarationKind.ReservedWord

TokenDeclaration as TokenDeclaration:
    TokenDeclarationKind TokenDeclarators OptionalTypeExpression => TokenDeclaration.New($1, $2, $3, @@)

OptionalTypeExpression as TypeExpression?:
    => None
    ':' TypeExpression => $2

TokenReference as TokenReference:
    name => TokenReference.NewNamed($1, @@)
    QuoteLiteral => TokenReference.NewLiteral($1, @@)

TokenReferences as [TokenReference]:
    TokenReference => Sequence.Create($1)
    TokenReferences ',' TokenReference => Sequence.Append($1, $3)

OperatorDeclarationKind as OperatorDeclarationKind:
    '%left' => OperatorDeclarationKind.Left
    '%right' => OperatorDeclarationKind.Right
    '%nonassoc' => OperatorDeclarationKind.Nonassociative
    '%shift' => OperatorDeclarationKind.Shift
    '%reduce' => OperatorDeclarationKind.Reduce

OperatorDeclaration as OperatorDeclaration:
    OperatorDeclarationKind TokenReferences => OperatorDeclaration.New($1, $2, @@)

StartDeclarator as Name:
    name => $1

StartDeclarators as [Name]:
    StartDeclarator => Sequence.Create($1)
    StartDeclarators ',' StartDeclarator => Sequence.Append($1, $3)

StartDeclarationKind as bool:
    '%start' => False
    '%xstart' => True

StartDeclaration as StartDeclaration:
    StartDeclarationKind StartDeclarators => StartDeclaration.New($1, $2, @@)

EndMarkerList as [TokenReference]:
    => default([TokenReference])
    '%' TokenReference => Sequence.Create($2)
    '%' '{' TokenReferences '}' => $3

GoalDeclarator as GoalDeclarator:
    name EndMarkerList => GoalDeclarator.New($1, $2, @@)

GoalDeclarators as [GoalDeclarator]:
    GoalDeclarator => Sequence.Create($1)
    GoalDeclarators ',' GoalDeclarator => Sequence.Append($1, $3)

GoalDeclaration as GoalDeclaration:
    '%goal' GoalDeclarators => GoalDeclaration.New($2, @@)

ExceptionDeclaration as ExceptionDeclaration:
    '%exception' NameList => ExceptionDeclaration.New($2, None, @@)
    '%exception' NameList ':' Name => ExceptionDeclaration.New($2, $4, @@)

DefineDeclaration as DefineDeclaration:
    '%define' DottedName Expression => DefineDeclaration.New($2, $3, @@)

Directive as Directive:
    TokenDeclaration => Directive.NewToken($1, @@)
    OperatorDeclaration => Directive.NewOperator($1, @@)
    StartDeclaration => Directive.NewStart($1, @@)
    GoalDeclaration => Directive.NewGoal($1, @@)
    ExceptionDeclaration => Directive.NewException($1, @@)
    DefineDeclaration => Directive.NewDefine($1, @@)

Directives as [Directive]:
    Directive NewLine => Sequence.Create($1)
    Directives Directive NewLine => Sequence.Append($1, $2)

DirectiveList as [Directive]:
    => default([Directive])
    Directives => $1

DirectiveDeclaration as DirectiveDeclaration:
    DirectiveList => DirectiveDeclaration.New($1, @@)

CharIntervalEndPoint as int:
    QuoteLiteral => ExtractCharIntervalEndPoint($1)

CharInterval as CharIntervalDescriptor:
    CharIntervalEndPoint => CreateCharInterval($1, $1, @1)
    CharIntervalEndPoint '-' CharIntervalEndPoint => CreateCharInterval($1, $3, @2)

CharIntervals as [CharIntervalDescriptor]:
    CharInterval => Sequence.Create($1)
    CharIntervals CharInterval => Sequence.Append($1, $2)

CharClassLiteral as CharClassDescriptor:
    '[' ']' => CharClassDescriptor.New(False, default([CharIntervalDescriptor]))
    '[^' ']' => CharClassDescriptor.New(True, default([CharIntervalDescriptor]))
    '[' CharIntervals ']' => CharClassDescriptor.New(False, $2)
    '[^' CharIntervals ']' => CharClassDescriptor.New(True, $2)

PrimaryLexicalExpression as LexicalExpression:
    StringLiteral => LexicalExpression.NewString($1, @@)
    QuoteLiteral => LexicalExpression.NewString($1, @@)
    CharClassLiteral => LexicalExpression.NewCharClass($1, @@)
    name => LexicalExpression.NewNameReference($1, @@)
    '(' ')' => LexicalExpression.NewEmpty(@@)
    '(' LexicalExpression ')' => $2

PostfixLexicalExpression as LexicalExpression:
    PrimaryLexicalExpression => $1
    PostfixLexicalExpression '*' => LexicalExpression.NewKleene($1, @@)
    PostfixLexicalExpression '?' => LexicalExpression.NewOptional($1, @@)
    PostfixLexicalExpression '+' => LexicalExpression.NewPositive($1, @@)
    PostfixLexicalExpression '{' NumberLiteral '}' =>:
        let count = ExtractIntOutOfNumberLiteral($3, @3)
        $$ = LexicalExpression.NewRepeat($1, count, count, @@)
    PostfixLexicalExpression '{' ',' NumberLiteral '}' =>:
        let count = ExtractIntOutOfNumberLiteral($4, @4)
        $$ = LexicalExpression.NewRepeat($1, None, count, @@)
    PostfixLexicalExpression '{' NumberLiteral ',' '}' =>:
        let count = ExtractIntOutOfNumberLiteral($3, @3)
        $$ = LexicalExpression.NewRepeat($1, count, None, @@)
    PostfixLexicalExpression '{' NumberLiteral ',' NumberLiteral '}' =>:
        let minCount = ExtractIntOutOfNumberLiteral($3, @3)
        let maxCount = ExtractIntOutOfNumberLiteral($5, @5)
        $$ = LexicalExpression.NewRepeat($1, minCount, maxCount, @@)

ConcatLexicalExpression as LexicalExpression:
    PostfixLexicalExpression => $1
    ConcatLexicalExpression PostfixLexicalExpression => LexicalExpression.NewConcat($1, $2, @@)

LexicalExpression as LexicalExpression:
    ConcatLexicalExpression => $1
    LexicalExpression '|' ConcatLexicalExpression => LexicalExpression.NewUnion($1, $3, @@)

LexicalAliasDeclarator as LexicalAliasDeclarator:
    name '=' LexicalExpression NewLine => LexicalAliasDeclarator.New($1, $3, @@)

LexicalAliasDeclaratorList as [LexicalAliasDeclarator]:
    LexicalAliasDeclarator => Sequence.Create($1)
    LexicalAliasDeclaratorList LexicalAliasDeclarator => Sequence.Append($1, $2)

LexicalAliasDeclarators as [LexicalAliasDeclarator]:
    LexicalAliasDeclaratorList => $1

OptionalLexicalAliasDeclarators as [LexicalAliasDeclarator]:
    => default([LexicalAliasDeclarator])
    LexicalAliasDeclarators => $1

LexicalAliasDeclaration as LexicalAliasDeclaration:
    LexicalAliasDeclarator => LexicalAliasDeclaration.New(Sequence.Create($1), @@)
    LexicalAliasDeclaration LexicalAliasDeclarator => LexicalAliasDeclaration.New($1.Items.Add($2), @@)

LexicalRuleDeclarator as LexicalRuleDeclarator:
    LexicalExpression NewLine => LexicalRuleDeclarator.New(False, $1, False, None, @@)
    LexicalExpression '$' NewLine => LexicalRuleDeclarator.New(False, $1, True, None, @@)
    '^' LexicalExpression NewLine => LexicalRuleDeclarator.New(True, $2, False, None, @@)
    '^' LexicalExpression '$' NewLine => LexicalRuleDeclarator.New(True, $2, True, None, @@)
    LexicalExpression SemanticAction => LexicalRuleDeclarator.New(False, $1, False, $2, @@)
    LexicalExpression '$' SemanticAction => LexicalRuleDeclarator.New(False, $1, True, $3, @@)
    '^' LexicalExpression SemanticAction => LexicalRuleDeclarator.New(True, $2, False, $3, @@)
    '^' LexicalExpression '$' SemanticAction => LexicalRuleDeclarator.New(True, $2, True, $4, @@)

LexicalRuleDeclaratorList as [LexicalRuleDeclarator]:
    LexicalRuleDeclarator => Sequence.Create($1)
    LexicalRuleDeclaratorList LexicalRuleDeclarator => Sequence.Append($1, $2)

LexicalRuleDeclarators as [LexicalRuleDeclarator]:
    LexicalRuleDeclaratorList => $1

OptionalLexicalRuleDeclarators as [LexicalRuleDeclarator]:
    => default([LexicalRuleDeclarator])
    LexicalRuleDeclarators => $1

SemanticAction as SemanticAction:
    '=>' Expression NewLine => SemanticAction.NewSimple($2, @@)
    '=>:' SimpleStatement NewLine => SemanticAction.NewFast($2, @@)
    '=>:' NewLine Indent StatementList Unindent => SemanticAction.NewFull($4, @@)

LexicalStartReferenceList as [Name]:
    name => Sequence.Create($1)
    LexicalStartReferenceList ',' name => Sequence.Append($1, $3)

LexicalStartReferenceSet as LexicalStartReferenceSet:
    name => LexicalStartReferenceSet.New(Sequence.Create($1), False, False, @@)
    '<' '**' '>' => LexicalStartReferenceSet.New(default([Name]), False, True, @@)
    '<' '*' '>' => LexicalStartReferenceSet.New(default([Name]), True, False, @@)
    '<' LexicalStartReferenceList '>' => LexicalStartReferenceSet.New($2, False, False, @@)
    '<' LexicalStartReferenceList ',' '*' '>' => LexicalStartReferenceSet.New($2, True, False, @@)

LexicalRuleDeclaration as LexicalRuleDeclaration:
    LexicalRuleDeclarators => LexicalRuleDeclaration.New(LexicalStartReferenceSet.New(default([Name]), True, False), $1, None, @@)
    LexicalRuleDeclarators 'default' SemanticAction => LexicalRuleDeclaration.New(LexicalStartReferenceSet.New(default([Name]), True, False), $1, $3, @@)
    'default' SemanticAction => LexicalRuleDeclaration.New(LexicalStartReferenceSet.New(default([Name]), True, False), default([LexicalRuleDeclarator]), $2, @@)

OptionalLexicalRuleDeclaration as LexicalRuleDeclaration:
    => LexicalRuleDeclaration.New(LexicalStartReferenceSet.New(default([Name]), True, False), default([LexicalRuleDeclarator]), None, @@)
    LexicalRuleDeclaration => $1

StandaloneLexicalRules as LexicalRuleDeclaration:
    LexicalRuleDeclaration => $1

OptionalStandaloneLexicalRules as LexicalRuleDeclaration:
    OptionalLexicalRuleDeclaration => $1

LexicalStartDeclaration as LexicalRuleDeclaration:
    LexicalStartReferenceSet ':' 'pass' NewLine => LexicalRuleDeclaration.New($1, default([LexicalRuleDeclarator]), None, @@)
    LexicalStartReferenceSet ':' NewLine Indent 'pass' NewLine Unindent => LexicalRuleDeclaration.New($1, default([LexicalRuleDeclarator]), None, @@)
    LexicalStartReferenceSet ':' NewLine Indent LexicalRuleDeclaration Unindent => LexicalRuleDeclaration.New($1, $5.Rules, $5.DefaultAction, @@)

LexicalStartDeclarationList as [LexicalRuleDeclaration]:
    LexicalStartDeclaration => Sequence.Create($1)
    LexicalStartDeclarationList LexicalStartDeclaration => Sequence.Append($1, $2)

LexicalStartDeclarations as [LexicalRuleDeclaration]:
    LexicalStartDeclarationList => $1

OptionalLexicalStartDeclaration as [LexicalRuleDeclaration]:
    => default([LexicalRuleDeclaration])
    LexicalStartDeclarations => $1

LexicalDeclaration as LexicalDeclaration:
    OptionalStandaloneLexicalRules OptionalLexicalStartDeclaration => LexicalDeclaration.New(LexicalAliasDeclaration.New(default([LexicalAliasDeclarator])), $1, $2, @@)
    LexicalAliasDeclaration OptionalStandaloneLexicalRules OptionalLexicalStartDeclaration => LexicalDeclaration.New($1, $2, $3, @@)

PrimarySyntacticExpression as SyntacticExpression:
    QuoteLiteral => SyntacticExpression.NewString($1, @@)
    name => SyntacticExpression.NewNameReference($1, @@)
    '(' ')' => SyntacticExpression.NewEmpty(@@)
    '(' SyntacticExpression ')' => $2
    '[' SyntacticExpression ']' => SyntacticExpression.NewOptional($2, True, @@)
    '{' SyntacticExpression '}' => SyntacticExpression.NewKleene($2, True, @@)
    '{' SyntacticExpression '}+' => SyntacticExpression.NewPositive($2, True, @@)

PostfixSyntacticExpression as SyntacticExpression:
    PrimarySyntacticExpression => $1
    PostfixSyntacticExpression '*' => SyntacticExpression.NewKleene($1, False, @@)
    PostfixSyntacticExpression '?' => SyntacticExpression.NewOptional($1, False, @@)
    PostfixSyntacticExpression '+' => SyntacticExpression.NewPositive($1, False, @@)
    PostfixSyntacticExpression '%' QuoteLiteral => SyntacticExpression.NewSequence($1, True, $3, @@)
    PostfixSyntacticExpression '%+' QuoteLiteral => SyntacticExpression.NewSequence($1, False, $3, @@)

ConcatSyntacticExpression as SyntacticExpression:
    PostfixSyntacticExpression => $1
    ConcatSyntacticExpression PostfixSyntacticExpression => SyntacticExpression.NewConcat($1, $2, @@)

SyntacticExpression as SyntacticExpression:
    ConcatSyntacticExpression => $1
    SyntacticExpression '|' ConcatSyntacticExpression => SyntacticExpression.NewUnion($1, $3, @@)

SyntacticRuleDeclarator as SyntacticRuleDeclarator:
    SyntacticExpression NewLine => SyntacticRuleDeclarator.New($1, None, None, @@)
    SyntacticExpression '%prec' TokenReference NewLine => SyntacticRuleDeclarator.New($1, $3, None, @@)
    SyntacticExpression '%prec' TokenReference SemanticAction => SyntacticRuleDeclarator.New($1, $3, $4, @@)
    SyntacticExpression SemanticAction => SyntacticRuleDeclarator.New($1, None, $2, @@)
    '%prec' TokenReference NewLine => SyntacticRuleDeclarator.New(SyntacticExpression.NewEmpty(@@), $2, None, @@)
    '%prec' TokenReference SemanticAction => SyntacticRuleDeclarator.New(SyntacticExpression.NewEmpty(@@), $2, $3, @@)
    SemanticAction => SyntacticRuleDeclarator.New(SyntacticExpression.NewEmpty(@@), None, $1, @@)

SyntacticRuleDeclarators as [SyntacticRuleDeclarator]:
    SyntacticRuleDeclarator => Sequence.Create($1)
    SyntacticRuleDeclarators SyntacticRuleDeclarator => Sequence.Append($1, $2)

SyntacticRuleDeclaration as SyntacticRuleDeclaration:
    name ':' 'pass' NewLine => SyntacticRuleDeclaration.New($1, None, default([SyntacticRuleDeclarator]), @@)
    name ':' NewLine Indent 'pass' NewLine Unindent => SyntacticRuleDeclaration.New($1, None, default([SyntacticRuleDeclarator]), @@)
    name ':' NewLine Indent SyntacticRuleDeclarators Unindent => SyntacticRuleDeclaration.New($1, None, $5, @@)
    name 'as' TypeExpression 'pass' NewLine => SyntacticRuleDeclaration.New($1, $3, default([SyntacticRuleDeclarator]), @@)
    name 'as' TypeExpression ':' NewLine Indent 'pass' NewLine Unindent => SyntacticRuleDeclaration.New($1, $3, default([SyntacticRuleDeclarator]), @@)
    name 'as' TypeExpression ':' NewLine Indent SyntacticRuleDeclarators Unindent => SyntacticRuleDeclaration.New($1, $3, $7, @@)

SyntacticRuleDeclarations as [SyntacticRuleDeclaration]:
    SyntacticRuleDeclaration => Sequence.Create($1)
    SyntacticRuleDeclarations SyntacticRuleDeclaration => Sequence.Append($1, $2)

OptionalSyntacticRuleDeclarations as [SyntacticRuleDeclaration]:
    => default([SyntacticRuleDeclaration])
    SyntacticRuleDeclarations => $1

SyntacticDeclaration as SyntacticDeclaration:
    OptionalSyntacticRuleDeclarations => SyntacticDeclaration.New($1, @@)
